﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Timers;
using A2DFramework.EventService.Configuration;

namespace A2DFramework.EventService.DistributeEventBus
{
    public class EventBusClientBrokerRunner
    {
        public string RemoteServer;
        public int RemotePort;
        public string ServerIdentity;
        public string DependencyDlls;
        private Timer tmer;

        public EventBusClientBrokerRunner(string remoteServer, int remotePort, string serverIdentity, string dependencyDlls, double retryConnectInterval)
        {
            this.RemoteServer = remoteServer;
            this.RemotePort = remotePort;
            this.ServerIdentity = serverIdentity;
            this.DependencyDlls = dependencyDlls;
            tmer = new Timer(retryConnectInterval);
            tmer.Enabled = false;
        }

        private EventBusClientBroker broker;
        public void On()
        {
            ReInit2EventServer();

            tmer.Elapsed += new ElapsedEventHandler(tmer_Elapsed);
            tmer.Enabled = true;
        }

        public void Publish<T>(T evt)
            where T : IEventBase
        {
            EnsureConnected();

            this.broker.Publish<T>(evt);
        }

        
        public void Publish(IEventBase evt)
        {
            EnsureConnected();

            this.broker.Publish(evt);
        }

        private void broker_NewEventReceived(string evtClass, object evt)
        {
            var result = from tb in EventServiceConfiguration.EventMapping
                         where tb.Key.Equals(evtClass)
                         select tb;

            foreach (KeyValuePair<Type, List<Type>> t in result.ToList())
            {
                foreach (Type tt in t.Value)
                {
                    Type targetType = tt;
                    MethodInfo mi = targetType.GetMethod("Handle");
                    if (mi == null)
                        continue;

                    object o = Activator.CreateInstance(targetType);
                    mi.Invoke(o, new object[] { evt });
                }
            }
        }


        private void ReInit2EventServer()
        {
            this.broker = new EventBusClientBroker(this.RemoteServer, this.RemotePort, this.ServerIdentity, this.DependencyDlls);
            this.broker.NewEventReceived += new EventReceived(broker_NewEventReceived);
            this.broker.Connect();

            List<Type> events = EventServiceConfiguration.EventMapping.Keys.Distinct().ToList();
            foreach (var evt in events)
                this.broker.Subscribe(evt);
        }
        private void EnsureConnected()
        {
            while (!this.broker.IsConnected())
                tmer_Elapsed(null, null);
        }

        private void tmer_Elapsed(object sender, ElapsedEventArgs e)
        {
            tmer.Enabled = false;
            if (this.broker != null && this.broker.IsConnected())
            {
                tmer.Enabled = true;
                return;
            }

            try
            {
                ReInit2EventServer();
            }
            catch (Exception ex)
            {
            }

            tmer.Enabled = true;
        }
    }
}
